package com.lora.web;

import com.acooly.core.utils.Dates;
import com.acooly.core.utils.Reflections;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.util.Base64Utils;

import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class BaseUtil {
    public static SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
    public static SimpleDateFormat dateTimeFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    private static Random random = new Random();

    /**
     * 判断对象是否为空
     * 创 建 人：bloody monday
     * 创建时间：2014-7-3 下午3:35:20
     * 修 改 人：bloody monday
     * 修改时间：2014-7-3 下午3:35:20
     * 方法描述：
     *
     * @param obj
     * @return
     */
    public static boolean isEmpty(Object obj) {
        if ("null".equals(obj) || obj == null) {
            return true;
        }
        String str = obj.toString();
        int strLen;
        if (str == null || (strLen = str.length()) == 0) {
            return true;
        }
        for (int i = 0; i < strLen; i++) {
            if ((Character.isWhitespace(str.charAt(i)) == false)) {
                return false;
            }
        }
        return true;
    }

    /**
     * 判断是否为数字
     *
     * @param str
     * @return
     */
    public static boolean isNumber(String str) {
        try {
            Double.parseDouble(str);
            return true;
        } catch (NumberFormatException e) {
            return false;
        }
    }

    /**
     * 将秒转换为00:00:00
     *
     * @param str
     * @return
     */
    public static String conversionSeconds(String str) {
        String result = "00:00:00";
        try {
            if (BaseUtil.isNumber(str)) {
                Long l = Long.parseLong(str);
                String temp1 = "";
                String temp2 = "";
                String temp3 = "";
                int t1 = (int) (l / 3600);
                int t2 = (int) (l % 3600) / 60;
                int t3 = (int) (l % 3600) % 60;
                if (t1 < 10) {
                    temp1 = "0" + t1;
                } else {
                    temp1 = t1 + "";
                }
                if (t2 < 10) {
                    temp2 = "0" + t2;
                } else {
                    temp2 = t2 + "";
                }
                if (t3 < 10) {
                    temp3 = "0" + t3;
                } else {
                    temp3 = t3 + "";
                }
                result = temp1 + ":" + temp2 + ":" + temp3;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 创 建 人：shutao<br/>
     * 创建时间：2015年5月6日 下午3:59:03<br/>
     * 修 改 人：shutao<br/>
     * 修改时间：2015年5月6日 下午3:59:03<br/>
     * 方法描述：获取指定范围的随机整数
     *
     * @param min
     * @param max
     * @return
     */
    public static int getRandom(int min, int max) {
        int i = min;
        try {
            i = random.nextInt(max) % (max - min + 1) + min;
        } catch (Exception e) {
        }
        return i;
    }

    /**
     * post请求 返回字节数组
     */
    public static byte[] sendPost(String url, String param) {
        byte[] byteArr = null;
        HttpURLConnection conn = null;
        OutputStreamWriter out = null;
        InputStream in = null;
        try {
            URL realUrl = new URL(url);
            // 打开和URL之间的连接
            conn = (HttpURLConnection) realUrl.openConnection();
            // 设置通用的请求属性
            conn.setRequestProperty("accept", "*/*");
            conn.setRequestProperty("connection", "Keep-Alive");
            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
            // 发送POST请求必须设置如下两行
            conn.setDoOutput(true);
            conn.setDoInput(true);
            conn.setReadTimeout(180000);
            conn.setConnectTimeout(180000);// 设置超时时间为3分钟
            conn.connect();
            // 获取URLConnection对象对应的输出流
            out = new OutputStreamWriter(conn.getOutputStream(), "utf-8");
            // 发送请求参数
            out.write(param);
            // flush输出流的缓冲
            out.flush();
            in = conn.getInputStream();
            byteArr = new byte[in.available()];
            in.read(byteArr);
        } catch (Exception e) {
        } finally {
            try {
                in.close();
                out.close();
                conn.disconnect();
            } catch (Exception e) {
            }
        }
        return byteArr;
    }

    /**
     * 创 建 人：shut<br/>
     * 创建时间：2016年3月22日 下午3:19:00<br/>
     * 修 改 人：shut<br/>
     * 修改时间：2016年3月22日 下午3:19:00<br/>
     * 方法描述：转化为表字段  userName ==> user_Name
     *
     * @param field
     * @return
     */
    public static String getTableField(String field) {
        String str = field;
        int count = 0;
        for (int i = 0; i < field.length(); i++) {
            char c = field.charAt(i);
            if (Character.isUpperCase(c)) {
                str = str.substring(0, i + count) + "_" + str.substring(i + count);
                count++;
            }
        }
        return str;
    }

    /**
     * 创 建 人：shut<br/>
     * 创建时间：2016年3月22日 下午3:18:35<br/>
     * 修 改 人：shut<br/>
     * 修改时间：2016年3月22日 下午3:18:35<br/>
     * 方法描述：创建查询条件 EQ_a.field1 ==> AND a.field1=''
     *
     * @param searchMap
     * @return
     */
    public static String createQueryCondition(Map<String, Object> searchMap) {
        StringBuffer sb = new StringBuffer("");
        try {
            for (Entry<String, Object> entry : searchMap.entrySet()) {
                // EQ_a.field1
                String key = entry.getKey().trim();
                if (!key.contains(".")) {
                    continue;
                }
                Object obj = entry.getValue();
                String value = "";// 值
                if (obj instanceof String[]) {
                    value = StringUtils.join((String[]) obj, ",");
                } else if (obj instanceof String) {
                    value = entry.getValue().toString();// 值
                }

                int first_ = key.indexOf("_");
                int first__ = key.indexOf(".");
                String oper = key.substring(0, first_);// 操作符
                String alias = key.substring(first_ + 1, first__);// 表别名
                if (StringUtils.isNotBlank(alias)) {
                    alias = alias + ".";
                }
                if (BaseUtil.isEmpty(value) && (!oper.equals("NULL")) && (!oper.equals("NOTNULL"))) {
                    continue;
                }
                String field = key.substring(first__ + 1);// 字段

                field = getTableField(field);
                value = StringEscapeUtils.escapeSql(value);// 处理sql特殊字符  如'等等

                switch (oper) {
                    case "EQ":
                        sb.append(" AND " + alias + field + "='" + value + "'");
                        break;
                    case "CON":// 包含
                        sb.append(" AND LOCATE(CONCAT('" + value + "',',')" + ", CONCAT(" + alias + "." + field + ",','))>0");
                        break;
                    case "LIKE":
                        sb.append(" AND " + alias + field + " LIKE '%" + value + "%'");
                        break;
                    case "LLIKE":
                        sb.append(" AND " + alias + field + " LIKE '%" + value + "'");
                        break;
                    case "RLIKE":
                        sb.append(" AND " + alias + field + " LIKE '" + value + "%'");
                        break;
                    case "GT":
                        // 范围查询只针对数字或则日期 其它无意义
                        // 判断是否是数字
                        if (isNumber(value)) {
                            sb.append(" AND " + alias + field + ">" + value + "");
                        } else {
                            sb.append(" AND " + alias + field + ">str_to_date('" + value + "', '%Y-%m-%d %T')");
                        }
                        break;
                    case "LT":
                        if (isNumber(value)) {
                            sb.append(" AND " + alias + field + "<" + value + "");
                        } else {
                            sb.append(" AND " + alias + field + "<str_to_date('" + value + "', '%Y-%m-%d %T')");
                        }
                        break;
                    case "GTE":
                        if (isNumber(value)) {
                            sb.append(" AND " + alias + field + ">=" + value + "");
                        } else {
                            sb.append(" AND " + alias + field + ">=str_to_date('" + value + "', '%Y-%m-%d %T')");
                        }
                        break;
                    case "LTE":
                        if (isNumber(value)) {
                            sb.append(" AND " + alias + field + "<=" + value + "");
                        } else {
                            sb.append(" AND " + alias + field + "<=str_to_date('" + value + "', '%Y-%m-%d %T')");
                        }
                        break;
                    case "NULL":
                        sb.append(" AND (" + alias + field + " IS NULL OR " + alias + field + "='')");
                        break;
                    case "NOTNULL":
                        sb.append(" AND " + alias + field + " IS NOT NULL");
                        sb.append(" AND " + alias + field + " <>''");
                        break;
                    case "IN":
                        Object[] array = value.split(",");
                        String temp = "";
                        for (int i = 0; i < array.length; i++) {
                            if (!BaseUtil.isEmpty(array[i]))
                                temp += "'" + StringEscapeUtils.escapeSql(array[i].toString()) + "',";
                        }
                        if (temp.length() > 0) {
                            temp = temp.substring(0, temp.length() - 1);
                        }
                        // IN
                        sb.append(" AND " + alias + field + " IN " + "(" + temp + ")");
                        break;
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("创建查询条件异常！");
        }
        return sb.toString();
    }

    /**
     * 方法描述：获取uuid
     *
     * @return
     */
    public static String getUUID() {
        String s = UUID.randomUUID().toString();
        return s.replaceAll("-", "");
    }



    /**
     * 方法描述：将对象转为map
     *
     * @param obj
     * @return
     */
    public static Map<String, Object> beanToMap(Object obj) {
        Map<String, Object> map = new HashMap<String, Object>(0);
        try {
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);
            for (int i = 0; i < descriptors.length; i++) {
                String name = descriptors[i].getName();
                if (!"class".equals(name)) {
                    map.put(name, propertyUtilsBean.getNestedProperty(obj, name));
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }


    public static <T> void bandEntity(Map<String, Object> map, T t) {
        String keyString = "";
        String keyValue = "";
        try {
            for (String key : map.keySet()) {
                keyString = key;
                keyValue = !BaseUtil.isEmpty(map.get(key)) ? map.get(key).toString() : "";
                try {
                    t.getClass().getDeclaredField(key).getType();
                } catch (Exception e) {
                    // TODO: handle exception
                    continue;
                }
                if (t.getClass().getDeclaredField(key).getType() == String.class) {
                    Reflections.invokeSetter(t, key, map.get(key));
                } else if (t.getClass().getDeclaredField(key).getType() == Long.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Long.parseLong(keyValue));
                    }
                } else if (t.getClass().getDeclaredField(key).getType() == Integer.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Integer.parseInt(keyValue));
                    }

                } else if (t.getClass().getDeclaredField(key).getType() == int.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Integer.parseInt(keyValue));
                    }
                } else if (t.getClass().getDeclaredField(key).getType() == Date.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Dates.parse(keyValue));
                    }

                } else if (t.getClass().getDeclaredField(key).getType() == Float.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Float.parseFloat(keyValue));
                    }

                } else if (t.getClass().getDeclaredField(key).getType() == Double.class) {
                    if (StringUtils.isBlank(keyValue)) {
                        Reflections.invokeSetter(t, key, null);
                    } else {
                        Reflections.invokeSetter(t, key, Double.parseDouble(keyValue));
                    }

                }
            }
        } catch (Exception e) {
            // TODO: handle exception
            System.out.println(keyString);
            e.printStackTrace();
        }

    }

    /**
     * 获得当前日期与本周一相差的天数 获得今天是一周的第几天，星期日是第一天，星期二是第二天......
     *
     * @return
     */
    public static int getMondayPlus() {
        Calendar cd = Calendar.getInstance();
        //
        int dayOfWeek = cd.get(Calendar.DAY_OF_WEEK);
        if (dayOfWeek == 1) {
            return -6;
        } else {
            return 2 - dayOfWeek;
        }
    }

    /**
     * 获得当前周- 周一的日期
     *
     * @return
     */
    public static String getCurrentMonday() {
        int mondayPlus = getMondayPlus();
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, mondayPlus);
        Date monday = currentDate.getTime();
        DateFormat df = DateFormat.getDateInstance();
        String preMonday = df.format(monday);
        return preMonday;
    }

    /**
     * 获得当前周- 周日 的日期
     *
     * @return
     */
    public static String getPreviousSunday() {
        int mondayPlus = getMondayPlus();
        GregorianCalendar currentDate = new GregorianCalendar();
        currentDate.add(GregorianCalendar.DATE, mondayPlus + 6);
        Date monday = currentDate.getTime();
        DateFormat df = DateFormat.getDateInstance();
        String preMonday = df.format(monday);
        return preMonday;
    }

    /**
     * 获得当前月--开始日期
     *
     * @param date
     * @return
     */
    public static String getMinMonthDate(String date) {
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(dateFormat.parse(date));
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMinimum(Calendar.DAY_OF_MONTH));
            return dateFormat.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获得当前月--结束日期
     *
     * @param date ymd
     * @return
     */
    public static String getMaxMonthDate(String date) {
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(dateFormat.parse(date));
            calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
            return dateFormat.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取当前date
     *
     * @return String
     */
    public static String getCurrentDate() {
        return dateFormat.format(new Date());
    }

    /**
     * 获取当前dateTime
     *
     * @return String
     */
    public static String getCurrentDateTime() {
        return dateTimeFormat.format(new Date());
    }

    /**
     * @param date 基准date
     * @param i    偏移数量
     * @return
     */
    @SuppressWarnings("static-access")
    public static String getDynamicDateToYear(String date, int i) {
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(dateFormat.parse(date));
            calendar.add(calendar.YEAR, i);
            return dateFormat.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * @param date 基准date
     * @param i    偏移数量
     * @return
     */
    @SuppressWarnings("static-access")
    public static String getDynamicDateToMonth(String date, int i) {
        Calendar calendar = Calendar.getInstance();
        try {
            calendar.setTime(dateFormat.parse(date));
            calendar.add(calendar.MONTH, i);
            return dateFormat.format(calendar.getTime());
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getDynamicDateToDay(String date, int i) {

        return "";
    }

    /**
     * 四舍五入
     *
     * @param s
     * @return
     */
    public static String DecimalFormat(String s) {
        if (BaseUtil.isEmpty(s) || !BaseUtil.isNumber(s)) {
            return s;
        }
        String arr[] = s.split("\\.");
        if (arr != null && arr.length == 2) {
            String ss = arr[1];
            if (!BaseUtil.isEmpty(ss) && ss.length() > 2) {
                String sss = ss.substring(2, 3);
                String s2 = ss.substring(0, 2);
                if (BaseUtil.isNumber(sss) && Integer.parseInt(sss) > 4) {
                    if (BaseUtil.isNumber(s2)) {
                        if (Integer.parseInt(s2) < 10) {
                            s2 = "0" + (Integer.parseInt(s2) + 1) + "";
                        } else {
                            s2 = (Integer.parseInt(s2) + 1) + "";
                        }
                    }
                }
                s = arr[0] + "." + s2;
            }
        }
        return s;
    }

    /**
     * 半角转全角
     *
     * @param input
     * @return
     * @author yuwei'chen
     */
    public static String ToSBC(String input) {
        // 半角转全角：
        char[] c = input.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] == 32) {
                c[i] = (char) 12288;
                continue;
            }
            if (c[i] < 127)
                c[i] = (char) (c[i] + 65248);
        }
        return new String(c);
    }

    /**
     * 全角转半角
     *
     * @param input
     * @return
     * @author yuwei'chen
     */
    public static String ToDBC(String input) {
        char[] c = input.toCharArray();
        for (int i = 0; i < c.length; i++) {
            if (c[i] == 12288) {
                c[i] = (char) 32;
                continue;
            }
            if (c[i] > 65280 && c[i] < 65375)
                c[i] = (char) (c[i] - 65248);
        }
        return new String(c);
    }

    /**
     * 是否包含数字
     * <pre>
     * isContainNumber("") false
     * isContainNumber("222") true
     * isContainNumber("222xxx") true
     * isContainNumber("xxx") false
     * isContainNumber("   ") false
     * </pre>
     *
     * @param str
     * @return Boolean
     * @author yuwei'chen
     */
    public static boolean isContainNumber(String str) {
        if (StringUtils.isBlank(str))
            return false;
        return str.matches(".*\\d+.*");
    }

    /**
     * 是否包含英文
     * <pre>
     * isContainAlpha("") false
     * isContainAlpha("222") false
     * isContainAlpha("222xxx") true
     * isContainAlpha("xxx") true
     * isContainAlpha("  ") false
     * </pre>
     *
     * @param str
     * @return Boolean
     * @author yuwei'chen
     */
    public static boolean isContainAlpha(String str) {
        if (StringUtils.isBlank(str))
            return false;
        return str.matches(".*[a-zA-Z]+.*");
    }

    /**
     * 随机生成小写英文
     *
     * @param i 生成位数
     * @return
     * @author yuwei'chen
     */
    public static String randomAlpha(int i) {
        String str = "";
        for (int j = 0; j < i; j++) {
            str += (char) (Math.random() * 26 + 'a');
        }
        return str;
    }


    /**
     * 方法描述：密码强度
     *
     * @param pwd
     * @return 111 ==> false 111111 ==> false aaaaaa ==> false 1qqqqq ==> true
     * 1!!!!! ==> true
     */
    public static boolean pwdStrength(String pwd) {
        return Pattern.matches(
                "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9a-zA-Z`~!@#$%^&*\\(\\)-_=+\\[\\]\\{\\}|\\\\;:'\",.<>/?]{6,16}$", pwd);
    }

    /**
     * 方法描述：随机生成一个字母
     *
     * @return
     */
    public static char getRandomChar() {
        String chars = "abcdefghijklmnopqrstuvwxyz";
        return chars.charAt(getRandom(0, 25));
    }

    public static String removeLastStr(String str, String s) {
        return str.substring(0, str.lastIndexOf(s));
    }

    public static String removeLastStr(StringBuffer sb, String s) {
        return sb.substring(0, sb.lastIndexOf(s));
    }

    /**
     * 对象list 转单字段list
     *
     * @param ja
     * @param field
     * @return
     */
    public static JSONArray arrObj2arrSingle(JSONArray ja, String field) {
        JSONArray list = new JSONArray();
        for (int i = 0; i < ja.size(); i++) {
            JSONObject o = (JSONObject) ja.get(i);
            list.add(o.get(field).toString());
        }
        return list;
    }

    /**
     * 对象list 转单字段set
     *
     * @param ja
     * @param field
     * @return
     */
    public static Set<Object> arrObj2arrSingleSet(JSONArray ja, String field) {
        Set<Object> list = new HashSet<>();
        for (int i = 0; i < ja.size(); i++) {
            JSONObject o = (JSONObject) ja.get(i);
            list.add(o.get(field));
        }
        return list;
    }

    public static JSONObject generalJo(boolean success, String msg) {
        return generalJo(success, msg, null);
    }

    public static JSONObject generalJo(boolean success, String msg, Object data) {
        JSONObject jo = new JSONObject();
        jo.put("success", success);
        jo.put("msg", msg);
        if (!isEmpty(data))
            jo.put("data", data);
        return jo;
    }

    /**
     * join
     *
     * @param set List &lt;?&gt; ? 不能为对象
     * @return
     */
    public static String joinSingleSet(List<?> set) {
        String str = "";
        for (Object object : set) {
            str += "'" + object + "',";
        }
        if (str.endsWith(",")) {
            str = str.substring(0, str.length() - 1);
        }
        return str;
    }

    /**
     * 根据对象实体获取指定字段key,val
     *
     * @param list 对象或map list
     * @param key  key字段
     * @param val  val字段
     * @return
     */
    public static Map<Object, Object> getKVByList(List<?> list, String key, String val) {
        JSONArray array = (JSONArray) JSONArray.toJSON(list);
        Map<Object, Object> map = Maps.newHashMap();
        try {
            for (Object object : array) {
                JSONObject o = (JSONObject) object;
                map.put(o.get(key), o.get(val));
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return map;
    }

    /**
     * 处理sql特殊字符
     * <p>
     * 例如,
     *
     * <pre>
     * statement
     * 		.executeQuery("SELECT * FROM MOVIES WHERE TITLE='" + StringEscapeUtils.escapeSql("McHale's Navy") + "'");
     * </pre>
     * </p>
     *
     * @param str the string to escape, may be null
     * @return a new String, escaped for SQL, <code>null</code> if null string input
     */
    public static String escapeSql(String str) {
        if (str == null) {
            return null;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < str.length(); i++) {
            char s = str.charAt(i);
            switch (s) {
                case '\'':
                    sb.append("''");
                    break;
                case '\\':
                    sb.append('\\');// mysql
                default:
                    sb.append(s);
                    break;
            }
        }
        return sb.toString();
    }

    /**
     * base64 转成hex
     * @param base64
     * @return
     */
    public static String base64ToHex(String base64) {
        byte[] sources = Base64Utils.decodeFromString(base64);
        StringBuilder sb = new StringBuilder();
        for(byte b : sources) {
            sb.append(Strings.padStart(Integer.toHexString(b & 0xff), 2, '0'));
        }
        return sb.toString();
    }
}
